//
//$Id: ode1ivp_ga.h 441 2010-04-09 17:27:20Z Oleg.Bulychov $
#pragma once

#include "projects/ode1ivp/ode1ivp.h"
#include "solvers/ga/ga_common.h"

//__________________________________________________________________________________
//__________________________________________________________________________________
template<>
struct solution<ODE1IVP_Solution, ga_tag>:
    public ODE1IVP_Solution
{
public:
    mutable double wheel_sector_;

    // one-point crossover at closest genes 
    template<class E>
    void cross(E* env, uniform_random& rnd, solution<ODE1IVP_Solution, ga_tag>& genome)
    {
        size_t j     = 1;
        double delta = Abs(y_[1] - genome.y_[1]);

        for (size_t i = 2; i <= env->cfg_.n_; ++i) 
        {
            double current_delta = Abs(y_[i] - genome.y_[i]);
            if (current_delta < delta)
            {
                j = i;
                delta = current_delta;
            }
        }

        for (size_t i = j; i <= env->cfg_.n_; ++i) 
            std::swap(y_[i], genome.y_[i]);

        changed_ = genome.changed_ = true;
    }


    // simple one-point crossover
    template<class E>
    void cross1(E* env, uniform_random& rnd, solution<ODE1IVP_Solution, ga_tag>& genome)
    {
        size_t j = 1 + rnd.next_SizeT(env->cfg_.n_);

        for (size_t i = j; i <= env->cfg_.n_; ++i) 
            std::swap(y_[i], genome.y_[i]);

        changed_ = genome.changed_ = true;
    }


    // one-point blending crossover
    template<class E>
    void cross2(E* env, uniform_random& rnd, solution<ODE1IVP_Solution, ga_tag>& genome)
    {
        size_t j     = 1 + rnd.next_SizeT(env->cfg_.n_);
        double delta = (y_[j] - genome.y_[j]) * rnd.next_Double();
        y_[j]        = y_[j]-delta;
        genome.y_[j] = genome.y_[j] + delta;

        for (size_t i = j+1; i <= env->cfg_.n_; ++i) 
            std::swap(y_[i], genome.y_[i]);

        changed_ = genome.changed_ = true;
    }


    // mutation in [y[i]-eps; y[i]+eps]
    template<class E>
    void mutate(E* env, uniform_random& rnd, double mutationProbability)
    {
        for (size_t i = 1; i <= env->cfg_.n_; ++i)
        {
            if (rnd.next_Double() < mutationProbability)
            {
                y_[i] = y_[i] + env->cfg_.eps_ * (1 - 2 * rnd.next_Double()); // old y_[i]-eps_ < new y_[i] < old y_[i]+eps_
                changed_ = true;
            }
        }
    }

    TCostType get_Fitness() const { return get_Cost(); }
};
//__________________________________________________________________________________

//EOF!
